/*
 * @Author: 0x9DEFA478
 * @Date: 2025-10-03 22:17:24
 * @LastEditTime: 2025-10-04 19:38:14
 * @LastEditors: 0x9DEFA478
 * @Description: 
 * 
 */
#include "./IO_Overlapped.hpp"
#include "./Error.hpp"
#include "../../H_FIFO.hpp"
#include "../../Utility/H_String.hpp"
#include <stdexcept>




namespace SystemAPI{

  namespace Windows{

#if defined(_WIN32)

    class Overlapped{
      public:
        Overlapped();
        ~Overlapped()noexcept;

        OVERLAPPED* Reset()noexcept;
        bool Wait(int Timeout)noexcept;

        OVERLAPPED* GetHandle()noexcept{return &overlapped;}

      private:
        OVERLAPPED overlapped;
    };

    Overlapped::Overlapped(){
      overlapped.Offset=0;
      overlapped.OffsetHigh=0;
      overlapped.hEvent=CreateEvent(nullptr,TRUE,FALSE,nullptr);
      if(overlapped.hEvent==nullptr){
        throw std::runtime_error("Overlapped::Overlapped() CreateEvent Fail: "+SystemAPI::Windows::GetErrorString());
      }
    }

    Overlapped::~Overlapped()noexcept{
      CloseHandle(overlapped.hEvent);
    }

    OVERLAPPED* Overlapped::Reset()noexcept{
      overlapped.Offset=0;
      overlapped.OffsetHigh=0;
      return &overlapped;
    }

    bool Overlapped::Wait(int Timeout)noexcept{
      return WaitForSingleObject(overlapped.hEvent,Timeout)==WAIT_OBJECT_0;
    }

    static int WaitOverlapped(HANDLE handle,Overlapped* overlapped,int Timeout){
      DWORD NumberOfBytesTransferred;

      if(!overlapped->Wait(Timeout)){
        return -1;
      }
      if(FALSE==GetOverlappedResult(handle,overlapped->GetHandle(),&NumberOfBytesTransferred,FALSE)){
        auto err=GetLastError();
        if(err==ERROR_HANDLE_EOF){
          return 0;
        }
        if(err==ERROR_OPERATION_ABORTED){
          return -2;
        }
        throw std::runtime_error("GetOverlappedResult 失败: "+SystemAPI::Windows::GetErrorStringWithErrorCode(err));
      }

      return NumberOfBytesTransferred;
    }

    struct IO_Overlapped_Data{
      Overlapped readOverlapped;
      DWORD NumberOfBytesRead;
      Overlapped writeOverlapped;
    };


    IO_Overlapped::IO_Overlapped():privateData(nullptr),handle(nullptr){}

    IO_Overlapped::IO_Overlapped(Handle&& handle):privateData(static_cast<void*>(new IO_Overlapped_Data)),handle(std::move(handle)){}

    IO_Overlapped::~IO_Overlapped()noexcept{
      if(privateData!=nullptr){
        delete static_cast<IO_Overlapped_Data*>(privateData);
      }
    }

    IO_Overlapped::IO_Overlapped(IO_Overlapped&& io_overlapped)noexcept:privateData(io_overlapped.privateData),handle(std::move(io_overlapped.handle)){
      io_overlapped.privateData=nullptr;
    }

    IO_Overlapped& IO_Overlapped::operator=(IO_Overlapped&& io_overlapped)noexcept{
      if(privateData!=nullptr){
        delete static_cast<IO_Overlapped_Data*>(privateData);
      }
      privateData=io_overlapped.privateData;
      handle=std::move(io_overlapped.handle);
      io_overlapped.privateData=nullptr;
      return *this;
    }

    void IO_Overlapped::ReadFile(void* Buffer,int BufferSize){
      auto pdata=static_cast<IO_Overlapped_Data*>(privateData);

      if(FALSE==::ReadFile(handle.GetHandle(),Buffer,BufferSize,&pdata->NumberOfBytesRead,pdata->readOverlapped.Reset())){
        auto err=GetLastError();
        if(err!=ERROR_IO_PENDING){
          throw std::runtime_error("ReadFile 失败: "+SystemAPI::Windows::GetErrorStringWithErrorCode(err));
        }
      }
    }

    int IO_Overlapped::WaitRead(int Timeout){
      auto pdata=static_cast<IO_Overlapped_Data*>(privateData);
      return WaitOverlapped(handle.GetHandle(),&pdata->readOverlapped,Timeout);
    }

    void IO_Overlapped::CancelRead(){
      auto pdata=static_cast<IO_Overlapped_Data*>(privateData);
      CancelIoEx(handle.GetHandle(),pdata->readOverlapped.GetHandle());
    }

    void IO_Overlapped::WriteFile(const void* Data,int DataLength){
      auto pdata=static_cast<IO_Overlapped_Data*>(privateData);

      if(FALSE==::WriteFile(handle.GetHandle(),Data,DataLength,&pdata->NumberOfBytesRead,pdata->writeOverlapped.Reset())){
        auto err=GetLastError();
        if(err!=ERROR_IO_PENDING){
          throw std::runtime_error("WriteFile 失败: "+SystemAPI::Windows::GetErrorStringWithErrorCode(err));
        }
      }
    }
    
    int IO_Overlapped::WaitWrite(int Timeout){
      auto pdata=static_cast<IO_Overlapped_Data*>(privateData);
      return WaitOverlapped(handle.GetHandle(),&pdata->writeOverlapped,Timeout);
    }

    void IO_Overlapped::CancelWrite(){
      auto pdata=static_cast<IO_Overlapped_Data*>(privateData);
      CancelIoEx(handle.GetHandle(),pdata->writeOverlapped.GetHandle());
    }

#endif

  }

}



